package ru.hei.pointsserver.service

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.mockito.Mockito.*
import reactor.core.publisher.Mono
import ru.hei.pointsserver.entities.House
import ru.hei.pointsserver.entities.PointsLog
import ru.hei.pointsserver.repository.HousesRepository
import ru.hei.pointsserver.repository.PointsLogRepository
import ru.hei.pointsserver.repository.ProfessorRepository
import ru.hei.pointsserver.rest.entities.request.AddPoints
import java.util.*
import kotlin.random.Random

class HouseServiceTest {
  private val professorRepository: ProfessorRepository = mock(ProfessorRepository::class.java)
  private val housesRepository: HousesRepository = mock(HousesRepository::class.java)
  private val pointsLogRepository: PointsLogRepository = mock(PointsLogRepository::class.java)

  private val service = PointsService(professorRepository, housesRepository, pointsLogRepository)

  @Nested
  inner class AddHouseTests {
    @Test
    fun `Should add points when professor exists`() {
      // Given
      val house = "some-house"
      val professorId = UUID.randomUUID()
      val pointsRequest = AddPoints(professorId, 10)
      val existingHouse = House(Random.nextLong(), house, 0)
      `when`(professorRepository.existsById(professorId)).thenReturn(Mono.just(true))
      `when`(housesRepository.findByNameIgnoreCase(house)).thenReturn(Mono.just(existingHouse))
      `when`(housesRepository.save(any(House::class.java)))
        .thenReturn(Mono.just(existingHouse.copy(points = 10)))
      `when`(pointsLogRepository.save(any(PointsLog::class.java))).thenReturn(
        Mono.just(PointsLog(professorId = professorId, points = 10, houseId = existingHouse.id!!))
      )

      // When
      val result = service.addPoints(house, pointsRequest)

      // Then
      assertThat(result.block()!!.points).isEqualTo(10)
      verify(pointsLogRepository, times(1)).save(any(PointsLog::class.java))
    }

    @Test
    fun `Should not add points when professor not found`() {
      // Given
      val house = "some-house"
      val professorId = UUID.randomUUID()
      val pointsRequest = AddPoints(professorId, 10)
      `when`(professorRepository.existsById(professorId)).thenReturn(Mono.just(false))

      // When
      val result = service.addPoints(house, pointsRequest)

      // Then
      verify(housesRepository, never()).save(any(House::class.java))
      verify(pointsLogRepository, never()).save(any(PointsLog::class.java))
      assertThat(result.block()).isNull()
    }
  }
}
